/**
 * The ConnectionCreationTool allows the user to create a new Connection
 * by dragging from the anchor point to the lead point of the connection.
 * The anchor and lead points have to lie inside shapes.
 * The tool will snap the anchor and lead positions to the origin of
 * the corresponding shapes.
 * 
 * @author Matthias.Hauswirth@usi.ch; Giuseppe Mendola (giuseppe.mendola@usi.ch);Gregory Banfi (gregory.banfi@usi.ch);
 */

package ch.usi.inf.pf2.gui;

import java.awt.event.MouseEvent;

import ch.usi.inf.pf2.Component;
import ch.usi.inf.pf2.Wire;
import ch.usi.inf.pf2.Gates.And;
import ch.usi.inf.pf2.Gates.Not;
import ch.usi.inf.pf2.Gates.Or;
import ch.usi.inf.pf2.pins.OutputPin;
import ch.usi.inf.pf2.puts.Input;
import ch.usi.inf.pf2.puts.Output;

public final class WireCreationTool extends Tool {

	private Wire wireUnderConstruction;
	private Component selectedComponent;
	//private ArrayList<InputPin> inputPins;
	//private OutputPin resultOutputPin;
	private OutputPin resultOutputPin;
	private int pin;

	public WireCreationTool(final Model model) {
		super(model, "Create wire", "wire.gif");
	//	inputPins = new ArrayList<InputPin>();
	}

	/**
	 * This method responds to the event mousePressed. When the mouse is pressed
	 * it is printed a message on the console, and it finds the component on
	 * which the user has pressed, then depending on what is the component it
	 * creates a wire object linked to the pin of the object, and it also get
	 * the value contains in the pressed component. Finally it adds the
	 * component to the drawing.
	 */
	@Override
	public void mousePressed(final MouseEvent ev) {
	//	System.out.println("mousePressed: " + ev);
		selectedComponent = getDrawing().findComponentAt(ev.getX(), ev.getY());
	//	resultOutputPin = new OutputPin(selectedComponent.getValue());
		if (selectedComponent != null) {
			if (selectedComponent instanceof And) {
				wireUnderConstruction = new Wire(
						selectedComponent.getOutputPin(),
						selectedComponent.getOriginX() + 40,
						selectedComponent.getOriginY() + 20, ev.getX(),
						ev.getY());

			} else if (selectedComponent instanceof Not) {
				wireUnderConstruction = new Wire(
						selectedComponent.getOutputPin(),
						selectedComponent.getOriginX() + 42,
						selectedComponent.getOriginY() + 20, ev.getX(),
						ev.getY());

			} else if (selectedComponent instanceof Or) {
				wireUnderConstruction = new Wire(
						selectedComponent.getOutputPin(),
						selectedComponent.getOriginX() + 95,
						selectedComponent.getOriginY() + 20, ev.getX(),
						ev.getY());
			} else if (selectedComponent instanceof Input) {
				wireUnderConstruction = new Wire(selectedComponent.getOutputPin(),
						selectedComponent.getOriginX() +((Input) selectedComponent).getWidth()+3,
						selectedComponent.getOriginY() + 10, ev.getX(),
						ev.getY());
			}
			getDrawing().add(wireUnderConstruction);
			selectedComponent.addOutConnectedWire(wireUnderConstruction);
		} else {
			wireUnderConstruction = null;
		}
	}

	/**
	 * This method responds to the event mouseDragged. When the mouse was
	 * dragging it is printed a message on the console, then it remove from the
	 * drawing the previous object and creates a new wire object linked to the
	 * pin of the previous object, and it also get the value contains in the
	 * pressed component. Finally it adds the component to the drawing.
	 */
	@Override
	public void mouseDragged(final MouseEvent ev) {
		//System.out.println("mouseDragged: " + ev);
		if (wireUnderConstruction != null) {
			getDrawing().remove(wireUnderConstruction);
			wireUnderConstruction.setStartPoint(
					wireUnderConstruction.getAnchorX(),
					wireUnderConstruction.getAnchorY());
			wireUnderConstruction.setFinalPoint(ev.getX(), ev.getY());
			getDrawing().add(wireUnderConstruction);
		}
	}

	/**
	 * This method responds to the event mouseReleased. When the mouse is
	 * released it is printed a message on the console, and the previous wire is
	 * removed, and it finds the component on which the user has released, then
	 * depending on what is the component it creates a wire object linked to the
	 * pin of the object, and it passes the value to the released component.
	 * Finally it adds the component to the drawing.
	 */
	@Override
	public void mouseReleased(final MouseEvent ev) {
		//System.out.println("mouseReleased: " + ev);
		if (wireUnderConstruction != null) {
			getDrawing().remove(wireUnderConstruction);
			final Component component = getDrawing().findComponentAt(ev.getX(),
					ev.getY());
			if (component != null) {

				int connectPosition = 15;

				if (component.hasFreePins()) {
					if (component.getFirstFreePin() == 1) {
						connectPosition = 15;
						pin = 0;
					} else if (component.getFirstFreePin() == 2) {
						pin = 1;
						connectPosition = 25;
					}

					if (component instanceof And) {
						wireUnderConstruction.setStartPoint(
								wireUnderConstruction.getAnchorX(),
								wireUnderConstruction.getAnchorY());
						wireUnderConstruction.setFinalPoint(
								component.getOriginX() - 5,
								component.getOriginY() + connectPosition);
						wireUnderConstruction.setInputPin(component
								.getInputPins().get(pin));
						component.setInputPins(component.getInputPins());
						wireUnderConstruction.run();
						component.compute(component.getInputPins());
						System.out.println(component.getInputPins().get(pin)
								.getValue());
						System.out.println(component.compute(
								component.getInputPins()).getValue());
					} else if (component instanceof Not) {
						wireUnderConstruction.setStartPoint(
								wireUnderConstruction.getAnchorX(),
								wireUnderConstruction.getAnchorY());
						wireUnderConstruction.setFinalPoint(
								component.getOriginX() - 5,
								component.getOriginY() + 20);
						
						
						wireUnderConstruction.setInputPin(component
								.getInputPins().get(pin));
						component.setInputPins(component.getInputPins());
						wireUnderConstruction.run();
						component.compute(component.getInputPins());
						System.out.println(component.getInputPins().get(pin)
								.getValue());
						System.out.println(component.compute(
								component.getInputPins()).getValue());
						
					} else if (component instanceof Or) {
						wireUnderConstruction.setStartPoint(
								wireUnderConstruction.getAnchorX(),
								wireUnderConstruction.getAnchorY());
						wireUnderConstruction.setInputPin(component
								.getInputPins().get(pin));
						component.setInputPins(component.getInputPins());
						wireUnderConstruction.run();
						component.compute(component.getInputPins());
						System.out.println(component.getInputPins().get(pin)
								.getValue());
						System.out.println(component.compute(
								component.getInputPins()).getValue());
						wireUnderConstruction.setFinalPoint(
								component.getOriginX() + 45,
								component.getOriginY() + connectPosition);

					} else if (component instanceof Output) {
						wireUnderConstruction.setStartPoint(
								wireUnderConstruction.getAnchorX(),
								wireUnderConstruction.getAnchorY());
						wireUnderConstruction.setFinalPoint(
								component.getOriginX() - 3,
								component.getOriginY() + 10);
						wireUnderConstruction.setInputPin(component
								.getInputPin());
						wireUnderConstruction.run();
						component.setOutputValue();
						System.out.println("OutputValue: "+component.getValue());
						
					}
					wireUnderConstruction.setConnectedComponent(component);
					getDrawing().add(wireUnderConstruction);
					getSelection().clear();
					getSelection().add(wireUnderConstruction);
					component.addInConnectedWire(wireUnderConstruction);
				}
			}

		}
	}
}
